package com.hero.herocat;

import com.hero.servlet.HeroRequest;
import com.hero.servlet.HeroResponse;
import com.hero.servlet.HeroServlet;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

import java.io.*;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;

/**
 * @author XiangXian
 * @version 1.0.0
 * @since 2024/3/31
 * <p>
 * /**
 * * HeroCat服务端处理器
 * *
 * * 1）从用户请求URI中解析出要访问的Servlet名称
 * * 2）从nameToServletMap中查找是否存在该名称的key。若存在，则直接使用该实例，否则执
 * 行第3）步
 * * 3）从nameToClassNameMap中查找是否存在该名称的key，若存在，则获取到其对应的全限定
 * 性类名，
 * * 使用反射机制创建相应的serlet实例，并写入到nameToServletMap中，若不存在，则直
 * 接访问默认Servlet
 * *
 */

public class CustomerHandler extends ChannelInboundHandlerAdapter {
    private static final String BASE_PATH = "/src/main/java/com/hero/webapp";

    private Map<String, HeroServlet> nameToServletMap;
    private Map<String, String> nameToClassNameMap;

    public CustomerHandler(Map<String, HeroServlet> nameToServletMap,
                           Map<String, String> nameToClassNameMap) {
        this.nameToServletMap = nameToServletMap;
        this.nameToClassNameMap = nameToClassNameMap;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws
            Exception {
        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            String uri = request.uri();
            //访问静态资源
            if (uri.contains("static")) {
                uri = URLDecoder.decode(uri, "UTF-8");
                Path currentPath = Paths.get("");
                String currentAbsolutePath = currentPath.toAbsolutePath().toString();
                String filePath = currentAbsolutePath + BASE_PATH + uri;

                File file = new File(filePath);
                if (!file.exists() || file.isHidden() || !file.isFile()) {
                    sendError(ctx, HttpResponseStatus.NOT_FOUND);
                    return;
                }
                try {
                    String content = readFileContent(file);
                    FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                            Unpooled.copiedBuffer(content, StandardCharsets.UTF_8));
                    response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
                    response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
                    ctx.writeAndFlush(response);
                } catch (IOException e) {
                    sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
                } finally {
                    ctx.close();
                }
                return;
            }
            //访问动态资源
            //aaa/bbb/twoservlet?name=aa
            String servletName = uri.substring(uri.lastIndexOf("/") + 1,
                    uri.indexOf("?"));
            HeroServlet heroServlet = new DefaultCustomServlet();
            if (nameToServletMap.containsKey(servletName)) {
                heroServlet = nameToServletMap.get(servletName);
            } else if (nameToClassNameMap.containsKey(servletName)) {
                // double-check，双重检测锁
                if (nameToServletMap.get(servletName) == null) {
                    synchronized (this) {
                        if (nameToServletMap.get(servletName) == null) {
                            // 获取当前Servlet的全限定性类名
                            String className = nameToClassNameMap.get(servletName);
                            // 使用反射机制创建Servlet实例
                            heroServlet = (HeroServlet)
                                    Class.forName(className).newInstance();
                            // 将Servlet实例写入到nameToServletMap
                            nameToServletMap.put(servletName, heroServlet);
                        }
                    }
                }
            } // end-else if
            // 代码走到这里，servlet肯定不空
            HeroRequest req = new HttpCustomRequest(request);
            HeroResponse res = new HttpCustomResponse(request, ctx);
            // 根据不同的请求类型，调用heroServlet实例的不同方法
            if (request.method().name().equalsIgnoreCase("GET")) {
                heroServlet.doGet(req, res);
            } else if (request.method().name().equalsIgnoreCase("POST")) {
                heroServlet.doPost(req, res);
            }
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,
                Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    private static String readFileContent(File file) throws IOException {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
        }
        return content.toString();
    }
}
